using System;
using System.Collections.Generic;
using System.Linq;
using Gj;
using UnityEngine;

namespace Gj_sparrow.Framework.Scripts.MapData
{
    public class Hotmap
    {
        public static Vector2Int R1 = new Vector2Int(1, 1);
        public static Vector2Int R2 = new Vector2Int(1, -1);
        public static Vector2Int R3 = new Vector2Int(-1, -1);
        public static Vector2Int R4 = new Vector2Int(-1, 1);
        public SizeGrid SG;
        public Action<Vector2Int> makeCb;

        public class HotGrid
        {
            public Vector2[] GetEdge(ref Vector2Int p, int distance)
            {
                // 分4个部分
                // +x+y，先固定x，y增加，减少x，获取所有边界点坐标列表
                // 填充 y不变，依次-x，到0，遍历所有边界的y点
                // -x+y，安+x+y对称获取，并填充，y不变，x取负
                // -x-y，安+x+y对称获取，并填充，y取负，x取负
                // +x-y，安+x+y对称获取，并填充，y取负，x不变
                var lineSlice = new List<Vector2>();
                var minX = distance*1f;
                for (var maxY = 0f; maxY <= distance; maxY+=1f)
                {
                    var d = Math.Sqrt(Math.Pow(minX, 2) + Math.Pow(maxY, 2));
                    var diff = d - distance;
                    if (diff > 0.5f)
                    {
                         minX -= 1f;
                         maxY -= 1f;
                         continue;
                    }
                    lineSlice.Add(new Vector2(minX, maxY));
                }
                var v1 = fillEdge(lineSlice, ref p, ref R1);
                var v2 = fillEdge(lineSlice, ref p, ref R2);
                var v3 = fillEdge(lineSlice, ref p, ref R3);
                var v4 = fillEdge(lineSlice, ref p, ref R4);
                var all = new Vector2[v1.Length+ v2.Length+v3.Length+v4.Length];
                var i = 0;
                // 按顺时针顺序加入all
                for (var j = v1.Length - 1; j >= 0; j--)
                {
                    var v = v1[j];
                    all[i] = v;
                    i++;
                }
                for (var j = 0; j < v2.Length; j++)
                {
                    var v = v2[j];
                    all[i] = v;
                    i++;
                }
                for (var j = v3.Length - 1; j >= 0; j--)
                {
                    var v = v3[j];
                    all[i] = v;
                    i++;
                }
                for (var j = 0; j < v4.Length; j++)
                {
                    var v = v4[j];
                    all[i] = v;
                    i++;
                }
                return all;
            }
            
            public Vector2[] fillEdge(List<Vector2> lineSlice, ref Vector2Int p, ref Vector2Int d)
            {
                var all = new List<Vector2> { };
                for (var index = 0; index < lineSlice.Count; index++)
                {
                    var p1 = lineSlice[index];
                    var p2 = new Vector2(p1.x*d.x, p1.y*d.y);
                    p2.x += p.x;
                    p2.y += p.y;
                    // Debug.LogError("fill:"+p1+""+d+"=>"+p2);
                    all.Add(p2);
                }

                return all.ToArray();
            }
            
            public Vector2Int[] fillIntEdge(List<Vector2Int> lineSlice, ref Vector2Int p, ref Vector2Int d)
            {
                var all = new List<Vector2Int> { };
                for (var index = 0; index < lineSlice.Count; index++)
                {
                    var p1 = lineSlice[index];
                    var p2 = new Vector2Int(p1.x*d.x, p1.y*d.y);
                    p2.x += p.x;
                    p2.y += p.y;
                    // Debug.LogError("fill:"+p1+""+d+"=>"+p2);
                    all.Add(p2);
                }

                return all.ToArray();
            }
            public Vector2Int[] fillRange(List<Vector2Int> lineSlice, ref Vector2Int p, ref Vector2Int d)
            {
                var all = new List<Vector2Int> { };
                for (var index = 0; index < lineSlice.Count; index++)
                {
                    var p1 = lineSlice[index];
                    for (var i = p1.x; i >= 0; i--)
                    {
                        var p2 = new Vector2Int(i*d.x, p1.y*d.y);
                        p2.x += p.x;
                        p2.y += p.y;
                        all.Add(p2);
                    }
                }

                return all.ToArray();
            }

            public Vector2Int[] GetPayloy(Vector2Int[] pp)
            {
                var all = new List<Vector2Int>();
                for (var i = 1; i < pp.Length; i++)
                {
                    var p1 = pp[i - 1];
                    var p2 = pp[i];
                    all.AddRange(setLine(ref p1, ref p2));
                }

                return all.ToArray();
            }

            public Vector2Int[] setLine(ref Vector2Int start, ref Vector2Int end)
            {
                var delta_x = end.x - start.x;
                var delta_y = end.y - start.y;
                var step = Math.Abs(delta_y);
                if (Math.Abs(delta_x) > Math.Abs(delta_y))
                {
                    step = Math.Abs(delta_x);
                }

                var x_step = (float)delta_x / step;
                var y_step = (float)delta_y / step;

                var x = (float)start.x;
                var y = (float)start.y;
                var points = new Vector2Int[step];
                for (var i = 0; i < step; i++)
                {
                    points[i] = new Vector2Int((int)Math.Round(x), (int)Math.Round(y));
                    x += x_step;
                    y += y_step;
                }

                return points;
            }

            public void Fill(ref Vector2Int position, int distance, List<Vector2Int> blocks, List<Vector2Int> edges)
            {
                var lineSlice = new List<Vector2Int>();
                for (var maxY = 0; maxY <= distance; maxY += 1)
                {
                    var v = new Vector2Int(distance, maxY);
                    if (!lineSlice.Contains(v))
                    {
                        lineSlice.Add(v);
                    }
                }
                for (var maxX = distance - 1; maxX >= 0; maxX -= 1)
                {
                    var v = new Vector2Int(maxX, distance);
                    if (!lineSlice.Contains(v))
                    {
                        lineSlice.Add(v);
                    }
                }
                var b1 = fillRange(lineSlice, ref position, ref R1);
                var b2 = fillRange(lineSlice, ref position, ref R2);
                var b3 = fillRange(lineSlice, ref position, ref R3);
                var b4 = fillRange(lineSlice, ref position, ref R4);
                for (int i = 0; i < b1.Length; i++)
                {
                    if (!blocks.Contains(b1[i])) blocks.Add(b1[i]);
                }
                for (int i = 0; i < b2.Length; i++)
                {
                    if (!blocks.Contains(b2[i])) blocks.Add(b2[i]);
                }
                for (int i = 0; i < b3.Length; i++)
                {
                    if (!blocks.Contains(b3[i])) blocks.Add(b3[i]);
                }
                for (int i = 0; i < b4.Length; i++)
                {
                    if (!blocks.Contains(b4[i])) blocks.Add(b4[i]);
                }
                var e1 = fillIntEdge(lineSlice, ref position, ref R1);
                var e2 = fillIntEdge(lineSlice, ref position, ref R2);
                var e3 = fillIntEdge(lineSlice, ref position, ref R3);
                var e4 = fillIntEdge(lineSlice, ref position, ref R4);
                for (int i = 0; i < e1.Length; i++)
                {
                    if (!edges.Contains(e1[i])) edges.Add(e1[i]);
                }
                for (int i = 0; i < e2.Length; i++)
                {
                    if (!edges.Contains(e2[i])) edges.Add(e2[i]);
                }
                for (int i = 0; i < e3.Length; i++)
                {
                    if (!edges.Contains(e3[i])) edges.Add(e3[i]);
                }
                for (int i = 0; i < e4.Length; i++)
                {
                    if (!edges.Contains(e4[i])) edges.Add(e4[i]);
                }
                // Debug.LogError("fill:"+position+" d:"+distance+" "+blocks.Count+":"+edges.Count);
            }
        }
        public HotGrid HG;
        
        public class RangeGrid
        {
            internal Hotmap hot;
            public List<Vector2Int> Positions;
            public Dictionary<int, List<Vector2Int>> Result;
            public Dictionary<int, List<int>> Neighbour;
            public Dictionary<int, List<Vector2Int>> Edge;
            public Func<Vector2Int, bool> CanHandler = (p) => true;
            public int[][] navigable;

            public bool ExistAndRegister(int source, ref Vector2Int to, ref Vector2Int from)
            {
                if (!CanHandler(to))
                {
                    List<Vector2Int> es;
                    if (!Edge.TryGetValue(source, out es))
                    {
                        es = new List<Vector2Int>();
                        Edge.Add(source, es);
                    }
                    if (!es.Contains(from))
                    {
                        es.Add(from);
                    }
                    return false;
                }
                var n = navigable[to.x][to.y];
                if (n > 0)
                {
                    if (n == source) return false;
                    
                    addNeighbour(source, n, ref to, ref from);
                    return false;
                }

                navigable[to.x][to.y] = source;
                List<Vector2Int> rs;
                if (!Result.TryGetValue(source, out rs))
                {
                    rs = new List<Vector2Int>();
                    Result.Add(source, rs);
                }
                rs.Add(to);
                return true;
            }

            private void addNeighbour(int source, int target, ref Vector2Int to , ref Vector2Int from)
            {
                List<int> rs;
                List<Vector2Int> es;
                {
                    if (!Neighbour.TryGetValue(source, out rs))
                    {
                        rs = new List<int>();
                        Neighbour.Add(source, rs);
                    }

                    if (!rs.Contains(target))
                    {
                        rs.Add(target);
                    }
                    if (!Edge.TryGetValue(source, out es))
                    {
                        es = new List<Vector2Int>();
                        Edge.Add(source, es);
                    }

                    if (!es.Contains(from))
                    {
                        es.Add(from);
                    }
                }
                
                {
                    if (!Neighbour.TryGetValue(target, out rs))
                    {
                        rs = new List<int>();
                        Neighbour.Add(target, rs);
                    }

                    if (!rs.Contains(source))
                    {
                        rs.Add(source);
                    }
                    if (!Edge.TryGetValue(target, out es))
                    {
                        es = new List<Vector2Int>();
                        Edge.Add(target, es);
                    }

                    if (!es.Contains(to))
                    {
                        es.Add(to);
                    }
                }
            }

            private void nnn(ref Vector2Int a, Dictionary<Vector2Int, Vector2Int> all, List<Vector3Int> result, ref Vector2Int tmp)
            {
                result.Clear();
                var neighours = HexDirectionExtensions.EVENQ[a.x & 1];
                for (var j = 5; j >= 0; j--)
                {
                     var jj = neighours[j];
                     tmp.x = jj[0] + a.x;
                     tmp.y = jj[1] + a.y;
                     if (all.ContainsKey(tmp))
                     {
                         result.Add(new Vector3Int(tmp.x,tmp.y, j));
                     }
                }
            }
            
            private void nn(ref Vector2Int a, Dictionary<Vector2Int, Vector2Int> all, List<Vector3Int> result, ref Vector2Int tmp, int dir, bool isOutline)
            {
                var neighours = HexDirectionExtensions.EVENQ[a.x & 1];
                 // var dir = -1; // 直接取最大方向，裁剪算法
                 result.Clear();
                 var c = a;
                 hot.SG.Restore(ref c);
                 var start = (dir + 3) % 6;
                 for (var j = 1; j <= 6; j++)
                 {
                     var d = isOutline ? start - j : start + j;
                     if (d < 0) d += 6;
                     if (d > 5) d -= 6;
                     var jj = neighours[d];
                     tmp.x = jj[0] + a.x;
                     tmp.y = jj[1] + a.y;
                     if (all.ContainsKey(tmp))
                     {
                         // if (!isOutline)
                         // {
                         //     result.Clear();
                         // }

                         result.Add(new Vector3Int(tmp.x, tmp.y, d));

                         // 判断3角点，不可走
                         if (!isOutline)
                         {
                             var prev = neighours[(d-1+6)%6];
                             tmp.x = prev[0] + a.x;
                             tmp.y = prev[1] + a.y;
                             if (!CanHandler(tmp)) break;
                             var next = neighours[(d+1)%6];
                             tmp.x = next[0] + a.x;
                             tmp.y = next[1] + a.y;
                             if (!CanHandler(tmp)) break;
                             result.Clear();
                             continue;
                         }
                         // j的方向是上一点到这点的方向
                         // var b = tmp;
                         // hot.SG.Restore(ref b);
                         // Debug.LogError("dir:"+c+"->"+b+" "+d);
                         // if (isOutline)
                         // {
                             break;
                         // }
                     }
                 }
            }

            public void TopEdge(List<Vector2Int> edges, ref Vector2Int tmp)
            {
                // 找寻最大y，最大x
                int first = -1;
                for(var i = 0; i < edges.Count; i++)
                {
                    Vector2Int e = edges[i];
                    if (first >= 0)
                    {
                        if (e.y < tmp.y)
                        {
                            continue;
                        }

                        if (e.y == tmp.y && e.x<=tmp.x)
                        {
                            continue;
                        }
                    }

                    first = i;
                    tmp.x = e.x;
                    tmp.y = e.y;
                }
            }

            public List<Vector3Int[]> SortEdge(List<Vector2Int> edges)
            {
                Vector2Int tmp = new Vector2Int();
                TopEdge(edges, ref tmp);
                // Debug.LogError("first("+edges.Count+"):"+tmp+"->"+first);
                // 找寻所有链接点
                var allPoint = new List<Vector2Int>(){};
                allPoint.AddRange(edges);
                allPoint.Remove(tmp);
                // var all = new List<Vector2Int>(edges);
                var all = edges.ToDictionary((i) => i);
                // all.Remove(tmp);
                var result = new List<Vector3Int[]>();
                
                var f = 0;
                Vector2Int tmp1 = new Vector2Int();
                Vector2Int tmp2 = new Vector2Int(tmp.x, tmp.y);
                var tmp3 = new List<Vector3Int>() {};
                var tmp4 = new List<Vector3Int>() { new Vector3Int(tmp.x, tmp.y, -1) };
                var tmpCube = HexCube.FromOffset(tmp);
                while (true)
                {
                    allPoint.Remove(tmp2);
                    tmp1 = tmp2;
                    var isOutline = result.Count == 0;
                    nn(ref tmp1, all, tmp3, ref tmp2, tmp3.Count > 0 ? tmp3[0].z : isOutline ? -2 : 2, isOutline);

                    if (tmp3.Count == 0)
                    {
                        // 找不到一个点，直接失败，独立点
                        // throw new Exception("排序完毕，无法链接顶点");
                        LogTools.Error("排序完毕，无法链接顶点");
                        return new List<Vector3Int[]>();
                    }
                    tmp2.x = tmp3[0].x;
                    tmp2.y = tmp3[0].y;
                    if (tmp2 == tmp)
                    {
                        // 完成一圈
                        var z = tmp4[0];
                        z.z = tmp3[0].z;
                        tmp4[0] = z;
                        result.Add(tmp4.ToArray());
                        tmp4.Clear();

                        if (allPoint.Count >= 1)
                        {
                            // 开启新的一圈
                            f = 1;
                            TopEdge(allPoint, ref tmp);

                            tmp4.Add(new Vector3Int(tmp.x, tmp.y, -1));
                            // all.Remove(tmp);

                            tmp2.x = tmp.x;
                            tmp2.y = tmp.y;
                            tmpCube = HexCube.FromOffset(tmp);
                            continue;
                        }
                        break;
                    }

                    f = tmp4.Count;
                    tmp2.x = tmp3[0].x;
                    tmp2.y = tmp3[0].y;
                    // Debug.LogError("edge:"+tmp2+"->"+all.Count);
                    tmp4.Add(tmp3[0]);
                }
                if (tmp4.Count > 0)
                {
                    result.Add(tmp4.ToArray());
                }
               
                return result;
            }

            public void FilterEdges(Dictionary<Vector2Int, Vector2Int> all, List<Vector2Int> edges)
            {
                var f = 0;
                Vector2Int tmp1 = new Vector2Int();
                Vector2Int tmp2 = new Vector2Int();
                var tmp3 = new List<Vector3Int>(){};
                while (f < edges.Count)
                {
                    tmp1.x = edges[f].x;
                    tmp1.y = edges[f].y;
                    nnn(ref tmp1, all, tmp3, ref tmp2);
                    var a = tmp1;
                    hot.SG.Restore(ref a);
                    // Debug.LogError("filter:"+a+"->"+tmp3.Count);
                    if (tmp3.Count == 6)
                    {
                        edges.Remove(tmp1);
                    }
                    else
                    {
                        f += 1;
                    }
                }

                var ee = new List<Vector2Int>(edges);
                edges.Clear();
                for (var i = 0; i < ee.Count; i++)
                {
                    if (!edges.Contains(ee[i]))
                    {
                        edges.Add(ee[i]);
                    }
                }
            }
        }
        public RangeGrid RG;
        public Hotmap(Vector2Int center, Vector2Int size)
        {
            // Debug.LogError(center+":"+size);
            SG = new SizeGrid(center, size);
            HG = new HotGrid();
            RG = new RangeGrid();
            RG.hot = this;
            RG.navigable = new int[size.x][];
            for (var i = 0; i < size.x; i++)
            {
                RG.navigable[i] = new int[size.y];
            }
            RG.Positions = new List<Vector2Int>();
            RG.Result = new Dictionary<int, List<Vector2Int>>();
            RG.Neighbour = new Dictionary<int, List<int>>();
            RG.Edge = new Dictionary<int, List<Vector2Int>>();
        }
        public Vector2[] AddRange(Vector2Int position, int r){
            // 转成position坐标，进行拟合范围
            // 得到的边再转为offset坐标
            // SG.Tailor(ref position);
            var list = HG.GetEdge(ref position, r);
            for (var i = 0; i < list.Length; i++)
            {
                // SG.Restore(ref list[i]);
            }

            return list;
        }
        
        public static bool p2p(ref Vector3Int sourcePosition, ref Vector3Int targetPosition)
        {
            var r1 = sourcePosition.y;
            var r2 = targetPosition.y;
            return sourcePosition.x - r1 <= targetPosition.x + r2
                   && sourcePosition.x + r1 >= targetPosition.x - r2
                   && sourcePosition.y - r1 <= targetPosition.y + r2
                   && sourcePosition.y + r1 >= targetPosition.y - r2;
        }
        
        private void FindIntersection(Vector3Int current, List<Vector3Int> all, List<Vector3Int> result)
        {
            result.Add(current);
            all.Remove(current);
            List<int> rr;
            for (var i = 0; i < all.Count; i++)
            {
                var value = all[i];
                if (p2p(ref current, ref value))
                {
                    FindIntersection(value, all, result);
                }
            }
        }
        public Vector3Int[][] MergeRange(Vector3Int[] positions)
        {
            // 先分组，分组后合并点位求边
            var result = new List<Vector3Int[]>();
            var all = new List<Vector3Int>();
            var tmp1 = new List<Vector3Int>();
            var tmp2 = new List<Vector3Int>();
            for (var i = 0; i < positions.Length; i++)
            {
                var current = positions[i];
                all.Add(current);
            }
            while (all.Count > 0)
            {
                var top = all[0];
                tmp1.Clear();
                FindIntersection(top, all, tmp1);
                // Debug.LogError("range:"+result.Count+"->"+tmp1.Count);
                result.Add(tmp1.ToArray());
            }
            return result.ToArray();
        }
        
        // 画组成的所有范围边
        public Vector3Int[][] AddMulti(Vector3Int[] positions)
        {
            List<Vector2Int> blocks = new List<Vector2Int>();
            List<Vector2Int> edges = new List<Vector2Int>();
            List<Vector2Int> r1 = new List<Vector2Int>();
            List<Vector2Int> r2 = new List<Vector2Int>();
            // 把边的点在所有点里判断数量，6个点即是连接点，移除
            for (var i = 0; i < positions.Length; i++)
            {
                var current = new Vector2Int(positions[i].x, positions[i].y);
                SG.Tailor(ref current);
                r1.Clear();
                r2.Clear();
                HG.Fill(ref current, positions[i].z, r1, r2);
                edges.AddRange(r2);
                blocks.AddRange(r1);
            }

            if (positions.Length > 1)
            {
                var blockMap = blocks.ToDictionary((i => i));
                // Debug.LogError("filter start:"+blocks.Count+":"+edges.Count);
                RG.FilterEdges(blockMap, edges);
                // Debug.LogError("filter end:"+blocks.Count+":"+edges.Count);
            }
            
            var rc = RG.SortEdge(edges);
            return rc.ToArray();
            // return new Vector3Int[0][];
        }

        public void Append(Vector2Int position)
        {
            // Debug.LogError("position:"+position);
            SG.Tailor(ref position);
            // Debug.LogError("position tailor:"+position);
            if (RG.Positions.Contains(position))
            {
                return;
            }
            RG.Positions.Add(position);
        }

        public void AddAndData(Vector2Int position, Vector2Int[] block, Vector2Int[] neighbour, Vector2Int[] edge)
        {
            if (RG.Positions.Count == 0)
            {
                return;
            }

            SG.Tailor(ref position);
            var index = RG.Positions.IndexOf(position);
            var inlineBlock = new List<Vector2Int>(block);
            SG.Tailor(inlineBlock);
            RG.Result.Add(index+1, inlineBlock);
            
            var inlineNeighbour = new List<int>();
            foreach (var item in neighbour)
            {
                var t = item;
                SG.Tailor(ref t);
                var tt = RG.Positions.IndexOf(t);
                // Debug.LogError("nei:"+position+"->"+t+"");
                inlineNeighbour.Add(tt+1);
            }
            RG.Neighbour.Add(index+1, inlineNeighbour);
            
            var inlineEdge = new List<Vector2Int>(edge);
            SG.Tailor(inlineEdge);
            RG.Edge.Add(index+1, inlineEdge);
        }

        public void BindCan(Func<Vector2Int, bool> can)
        {
            RG.CanHandler = (position) =>
            {
                if (!SG.InBounds(position.x, position.y)) return false;
                SG.Restore(ref position);
                return can(position);
            };
        }

        public void Run()
        {
            var step = 0;
            var rr = new bool[RG.Positions.Count];
            //visit := []int{}
            var canList = new List<Vector2Int>[RG.Positions.Count];
            Vector2Int tmp1 = new Vector2Int();
            Vector2Int tmp2 = new Vector2Int();
            for(;;)
            {
                var times = 0;
                for (var index = 0; index < RG.Positions.Count; index++)
                {
                    var r = rr[index];
                    if (r)
                    {
                        times += 1;
                        continue;
                    }

                    var ll = canList[index];
                    var source = index + 1;
                    if (step == 0)
                    {
                        ll = new List<Vector2Int>(){RG.Positions[index]};
                    }

                    var flag = false;
                    List<Vector2Int> cans = null;
                    for (var i = 0; i < ll.Count; i++)
                    {
                        // var p = ll[i];
                        tmp1.x = ll[i].x;
                        tmp1.y = ll[i].y; 
                        var neighours = HexDirectionExtensions.EVENQ[tmp1.x & 1];
                        for (var j = 0; j < 6; j++)
                        {
                            var ni = neighours[j];
                            tmp2.x = tmp1.x + ni[0];
                            tmp2.y = tmp1.y + ni[1];
                            // Debug.LogError("tmp2"+tmp2);
                            // Debug.LogError("tmp1"+tmp1);
                            if (RG.ExistAndRegister(source, ref tmp2, ref tmp1))
                            {
                                flag = true;
                                if (cans == null) cans = new List<Vector2Int>();
                                cans.Add(tmp2);
                            }
                        }
                    }

                    if (!flag)
                    {
                        rr[index] = true;
                    }
                    else
                    {
                        canList[index] = cans;
                    }
                }

                if (times == RG.Positions.Count)
                {
                    break;
                }

                step += 1;
            }
            
        }

        public void DownloadData(out List<Vector2Int[]> result, out List<Vector2Int[]> neighbour,
            out List<Vector2Int[]> edge)
        {
            result = new List<Vector2Int[]>();
            neighbour = new List<Vector2Int[]>();
            edge = new List<Vector2Int[]>();
            // foreach (var item in RG.Positions)
            // {
            //     Debug.LogError(item.Key+""+ item.Value.ToArray());
            // }
            for (var i = 0; i < RG.Positions.Count; i++)
            {
                var p = RG.Positions[i];
                if (RG.Result.TryGetValue(i + 1, out var rr))
                {
                    rr.Remove(p);
                    rr.Insert(0, p);
                    var r = new List<Vector2Int>(rr);
                    SG.Restore(r);
                    result.Add(r.ToArray());
                    
                    // Debug.LogError("result:"+p+"->"+r[0]);
                }
                else
                {
                    var r = new Vector2Int[] { p };
                    SG.Restore(r);
                    result.Add(r);
                }

                if (RG.Edge.TryGetValue(i + 1, out var ee))
                {
                    // 测试边点是否能够连续：独木桥路的情况提前发现
                    try
                    {
                        RG.SortEdge(ee);
                        // Debug.LogError("edge finish:"+p);
                    }
                    catch (Exception exc)
                    {
                        foreach (var eee in ee)
                        {
                            var eeee = eee;
                            SG.Restore(ref eeee);
                            if (makeCb != null) makeCb(eeee);
                        }
                        Debug.LogException(exc);
                    }
                    var e = new List<Vector2Int>(ee);
                    SG.Restore(e);
                    
                    edge.Add(e.ToArray());
                }
                else
                {
                    edge.Add(new Vector2Int[0]);
                }
                var n = new List<Vector2Int>();
                if(RG.Neighbour.TryGetValue(i + 1, out var kk))
                {
                    foreach (var k in kk)
                    {
                        n.Add(RG.Positions[k-1]);
                    }
                    SG.Restore(n);
                }
                neighbour.Add(n.ToArray());
            }
        }

        public Vector2Int[] GetArea(Vector2Int position)
        {
            if (RG.Positions.Count == 0)
            {
                return null;
            }
            SG.Tailor(ref position);
            var index = RG.Positions.IndexOf(position);
            List<Vector2Int> rr;
            if (!RG.Result.TryGetValue(index+1, out rr))
            {
                return null;
            }

            var list = rr.ToArray();
            for (var i = 0; i < list.Length; i++)
            {
                SG.Restore(ref list[i]);
            }

            return list;
        }

        public List<Vector3Int[]> GetEdge(Vector2Int position)
        {
            // Debug.LogError("position all:"+RG.Positions.Count);
            // Debug.LogError("edge all:"+RG.Edge.Count);
            if (RG.Positions.Count == 0)
            {
                return null;
            }

            SG.Tailor(ref position);
            var index = RG.Positions.IndexOf(position);
            // Debug.LogError("edge:"+position+":->"+index+":"+RG.Positions.Count);
            List<Vector2Int> rr;
            if (!RG.Edge.TryGetValue(index+1, out rr))
            {
                return null;
            }
            // Debug.LogError("edge:"+rr.Count);
            
            try
            {
                var rc = RG.SortEdge(rr);
                return rc;
            }
            catch (Exception exc)
            {
                foreach (var eee in rr)
                {
                    var eeee = eee;
                    SG.Restore(ref eeee);
                    if (makeCb != null) makeCb(eeee);
                }
                Debug.LogException(exc);
            }

            return new List<Vector3Int[]>();
        }

        public Vector2Int[] FormatEdge(Vector3Int[] edges)
        {
            // Debug.LogError("format starrt"+SG.start);
            var result = new Vector2Int[edges.Length];
            for (var i = 0; i < edges.Length; i++)
            {
                var edge = edges[i];
                result[i] = new Vector2Int(edge.x, edge.y);
            }
            SG.Restore(result);
            return result;
        }

        private void FindNeighbour(int current, List<int> all, List<int> result)
        {
            result.Add(current);
            all.Remove(current);
            if (all.Count == 0)
            {
                return;
            }
            List<int> rr;
            if (!RG.Neighbour.TryGetValue(current+1, out rr))
            {
                return;
            }

            if (rr.Count == 0)
            {
                // 兼容没有邻居数据
                result.AddRange(all);
                all.Clear();
                return;
            }

            foreach (var r in rr)
            {
                // Debug.LogError("find:"+current+"->"+r);
                if (all.Contains(r-1))
                {
                    FindNeighbour(r-1, all, result);
                }
            }
        }
        
        public Vector2Int[][] MergeGroup(Vector2Int[] positions)
        {
            // 先分组，分组后合并点位求边
            var result = new List<Vector2Int[]>();
            var all = new List<int>();
            var tmp1 = new List<int>();
            var tmp2 = new List<int>();
            for (var i = 0; i < positions.Length; i++)
            {
                var current = positions[i];
                SG.Tailor(ref current);
                var index = RG.Positions.IndexOf(current);
                all.Add(index);
                // Debug.LogError("group:"+i+"->"+current);
            }
            while (all.Count > 0)
            {
                var top = all[0];
                tmp1.Clear();
                FindNeighbour(top, all, tmp1);
                var r = new Vector2Int[tmp1.Count];
                for (var i = 0; i < tmp1.Count; i++)
                {
                    var t = tmp1[i];
                    r[i] = RG.Positions[t];
                    // SG.Restore(ref r[i]);
                }
                // Debug.LogError("group:"+result.Count+"->"+r.Length+"<-"+all.Count);
                result.Add(r);
            }
            return result.ToArray();
        }

        // 同一组，并且相邻点都是邻居点
        public List<Vector3Int[]> MergeEdge(Vector2Int[] positions)
        {
            var all = new List<int>();
            for (var i = 0; i < positions.Length; i++)
            {
                var current = positions[i];
                // SG.Tailor(ref current);
                var index = RG.Positions.IndexOf(current);
                all.Add(index);
            }

            List<Vector2Int> blocks = new List<Vector2Int>();
            List<Vector2Int> edges = new List<Vector2Int>();
            List<Vector2Int> r1;
            List<Vector2Int> r2;
            // 把边的点在所有点里判断数量，6个点即是连接点，移除
            for (var i = 0; i < all.Count; i++)
            {
                if (!RG.Result.TryGetValue(all[i]+1, out r1))
                {
                    continue;
                }
                blocks.AddRange(r1);
                
                if (!RG.Edge.TryGetValue(all[i]+1, out r2))
                {
                    continue;
                }
                // 兼容没有生成边数据
                edges.AddRange(r2.Count==0?r1:r2);
            }

            var blocksMap = blocks.ToDictionary((i => i));
            if (positions.Length >= 1)
            {
                // Debug.LogError("filter start:"+blocks.Count+":"+edges.Count);
                RG.FilterEdges(blocksMap, edges);
                // Debug.LogError("filter end:"+blocks.Count+":"+edges.Count);
            }
            
            
            var rc = RG.SortEdge(edges);
            return rc;
            // return new Vector3Int[0][];
        }

        public List<Vector3Int[]> GenerateEdge(Vector2Int[] positions)
        {
            List<Vector2Int> blocks = new List<Vector2Int>(positions);
            List<Vector2Int> edges = new List<Vector2Int>(positions);
            var blockMap = blocks.ToDictionary((i => i));
            RG.FilterEdges(blockMap, edges);
            var rc = RG.SortEdge(edges);
            return rc;
        }

        public List<Vector3> EdgeToOutline(Vector3Int[] positions, bool isOutline, Vector3 offset)
        {
            // 已经是外部坐标，顺序边，按坐标计算得到边关系
            var outline = new List<Vector3>();
            var prev = positions[0].z;
            var metrics = HexMetrics.Default;
            var cur = new Vector2Int();
            for (var i = 0; i < positions.Length; i++)
            {
                cur.x = positions[i].x;
                cur.y = positions[i].y;
                SG.Restore(ref cur);
                var direction = i+1 >= positions.Length ? positions[0].z : positions[i + 1].z;
                var p = HexCube.FromOffset(cur, metrics).ToPosition();
                var targetDirection = isOutline ? prev - 3 : prev - 3;
                targetDirection = targetDirection >= 6
                    ? targetDirection - 6
                    : (targetDirection <= -1 ? targetDirection + 6 : targetDirection);
                // direction = isOutline ? direction : direction - 5;
                // if (!isOutline)
                // {
                //     Debug.LogError(positions[i]+":"+cur+":"+prev+"->"+direction+":"+targetDirection);
                // }
                var step = 0;
                while (targetDirection != direction || step == 0)
                {
                    step += 1;
                    targetDirection = isOutline ? targetDirection - 1 : targetDirection + 1;
                    targetDirection = targetDirection == 6 ? 0 : (targetDirection == -1 ? 5 : targetDirection);
                    if (targetDirection == direction) break;
                    if (step > 5)
                    {
                        throw new Exception("点位错误："+targetDirection+"->"+direction);
                    }

                    // if (!isOutline)
                    // {
                    //     Debug.LogError(targetDirection);
                    // }

                    var vertex = metrics.positionVERTEX[targetDirection];
                    outline.Add(new Vector3(p.x + vertex.x + offset.x, p.y + offset.y, p.z + vertex.y + offset.z));
                }

                prev = direction;
            }

            return outline;
        }

        public Vector2Int[] GetNeighbour(Vector2Int position)
        {
            if (RG.Positions.Count == 0)
            {
                return null;
            }

            SG.Tailor(ref position);
            var index = RG.Positions.IndexOf(position);
            List<int> rr;
            if (!RG.Neighbour.TryGetValue(index+1, out rr))
            {
                return null;
            }
            var s = new Vector2Int[rr.Count];
            for (var i = 0; i < rr.Count; i++)
            {
                s[i] = RG.Positions[rr[i]];
            }
            
            var list = s;
            for (var i = 0; i < list.Length; i++)
            {
                SG.Restore(ref list[i]);
            }

            return list;
        }
    }
}